#pragma once

#include "../mqcommon/mq_helper.hpp"
#include "../mqcommon/mq_logger.hpp"
#include "../mqcommon/mq_msg.pb.h"

#include <string>
#include <memory>
#include <unordered_map>
#include <sstream>
#include <mutex>

namespace mq
{
    // 队列描述数据类
    struct MsgQueue
    {
        using ptr = std::shared_ptr<MsgQueue>;
        std::string name;                                  // 队列名称
        bool durable;                                      // 持久化标志位
        bool exclusive;                                    // 是否独占 （还未实现此功能）
        bool auto_delete;                                  // 自动删除 （未实现）
        google::protobuf::Map<std::string, std::string> args; // 其他参数

        //在recovery函数里需要无参构造
        MsgQueue() {}
        MsgQueue(const std::string &qname, bool qdurable, bool qexclusive, bool qauto_delete,
                 const google::protobuf::Map<std::string, std::string> &qargs)
            : name(qname), durable(qdurable), exclusive(qexclusive), auto_delete(qauto_delete), args(qargs) {}

        //序列化和反序列化 我们需要将args存储在数据库中，所以提供这两个接口
        void setArgs(const std::string &str_args)
        {
            std::vector<std::string> result;
            StrHelper::split(str_args, "&", &result);
            for (auto &str : result)
            {
                auto pos = str.find('=');
                if (pos == std::string::npos)
                {
                    continue;
                }

                std::string key = str.substr(0, pos);
                std::string val = str.substr(pos + 1);
                args[key] = val;
            }
        }
        std::string getArgs()
        {
            std::string str;
            for (auto &it : args)
            {
                str += it.first;
                str += '=';
                str += it.second;
                str += '&';
            }
            return str;
        }
    };

    //队列数据持久化类
    class MsgQueueMapper
    {
    private:
        SqliteHelper _sql_helper;
    private:
        static int selectCallBack(void *arg, int numcol, char **row, char **fields)
        {
            std::unordered_map<std::string, MsgQueue::ptr> *result = static_cast<std::unordered_map<std::string, MsgQueue::ptr> *>(arg);
            MsgQueue::ptr mqp = std::make_shared<MsgQueue>();
            mqp->name = row[0];
            mqp->durable = (bool)std::stoi(row[1]);
            mqp->exclusive = (bool)std::stoi(row[2]);
            mqp->auto_delete = (bool)std::stoi(row[3]);
            if (row[4]) mqp->setArgs(row[4]);

            result->insert({mqp->name, mqp});

            return 0;
        }

    public:
        MsgQueueMapper(const std::string &dbfile) : _sql_helper(dbfile)
        {
            //创建父级目录
            const std::string &path = FileHelper::parentDirectory(dbfile);
            FileHelper::createDirectory(path);
            //创建/打开数据库文件
            assert(_sql_helper.open());
            //创建队列表格
            createTable();
        }
        ~MsgQueueMapper()
        {
            _sql_helper.close();
        }

        void createTable()
        {
            std::stringstream sql;
            sql << "create table if not exists queue_table(";
            sql << "name varchar(32) primary key, ";
            sql << "durable int, ";
            sql << "exclusive int, ";
            sql << "auto_delete int, ";
            sql << "args varchar(128));";
            assert(_sql_helper.exec(sql.str(), nullptr, nullptr));
        }
        void removeTable()
        {
            std::string sql = "drop table if exists queue_table;";
            assert(_sql_helper.exec(sql, nullptr, nullptr));
        }
        bool insert(const MsgQueue::ptr &mqp)
        {
            std::stringstream sql;
            sql << "insert into queue_table values(";
            sql << "'" << mqp->name << "', ";
            sql << mqp->durable << ", ";
            sql << mqp->exclusive << ", ";
            sql << mqp->auto_delete << ", ";
            sql << "'" << mqp->getArgs() << "');";
            return _sql_helper.exec(sql.str(), nullptr, nullptr);
        }
        void remove(const std::string &name)
        {
            std::stringstream sql;
            sql << "delete from queue_table where name=";
            sql << "'" << name << "';";
            _sql_helper.exec(sql.str(), nullptr, nullptr);
        }

        //用于重启恢复队列数据，直接返回哈希表
        std::unordered_map<std::string, MsgQueue::ptr> recovery()
        {
            std::unordered_map<std::string, MsgQueue::ptr> result;
            std::string sql = "select name,durable,exclusive,auto_delete,args from queue_table";
            _sql_helper.exec(sql, selectCallBack, &result);
            return result;
        }
    };

    //队列数据管理类
    class MsgQueueManager
    {
    private:
        std::mutex _mutex;
        MsgQueueMapper _mapper;
        std::unordered_map<std::string, MsgQueue::ptr> _msg_queues;
    public:
        using ptr = std::shared_ptr<MsgQueueManager>;
        MsgQueueManager(const std::string &dbfile) : _mapper(dbfile)
        {
            //从数据库中读取，恢复队列数据
            _msg_queues = _mapper.recovery();
        }

        //声明队列
        bool declareQueue(const std::string &name, bool durable, bool exclusive, bool auto_delete,
                          const google::protobuf::Map<std::string, std::string> &args)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _msg_queues.find(name);
            if (it != _msg_queues.end())
            {
                //存在则直接return 
                return true;
            }

            //不存在则构建
            auto mqp = std::make_shared<MsgQueue>(name, durable, exclusive, auto_delete, args);
            //持久化标志位true则插入至数据库
            if(durable == true){
                bool ret = _mapper.insert(mqp);
                if (ret == false)
                {
                    return false;
                }
            }
            //存放进哈希表中管理
            _msg_queues.insert({name, mqp});
            return true;
        }

        //删除队列
        void deleteQueue(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _msg_queues.find(name);
            if (it == _msg_queues.end())
            {
                //不存在就return
                return;
            }

            //持久化标志位存在才到数据库中删除
            if (it->second->durable == true) _mapper.remove(name);
            //从哈希表中删除
            _msg_queues.erase(name);
        }

        //获取指定队列
        MsgQueue::ptr selectQueue(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _msg_queues.find(name);
            if (it == _msg_queues.end())
            {
                //不存在则返回空对象
                return MsgQueue::ptr();
            }

            return it->second;
        }
        //返回所有队列
        std::unordered_map<std::string, MsgQueue::ptr> AllQueue()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _msg_queues; //这里构造了一个
        }
        //判断指定队列是否存在
        bool exists(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _msg_queues.find(name);
            if (it == _msg_queues.end())
            {
                return false;
            }

            return true;
        }
        //返回队列个数
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _msg_queues.size();
        }
        //销毁所有队列
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeTable();
            _msg_queues.clear();
        }
    };
}
